์๋ฒ ์ ์ก ์ด๋ฒคํธ(SSE)๋ฅผ ํ์ฉํ ์ค์๊ฐ ํ๋ก ํธ์๋ ์ ๋ฐ์ดํธ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์. ์คํธ๋ฆฌ๋ฐ ์๋ต์ ๊ตฌํํ์ฌ ๋์ฑ ๋์ ์ด๊ณ ๋งค๋ ฅ์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ง๋๋ ๋ฒ์ ์๊ฐํฉ๋๋ค.
ํ๋ก ํธ์๋ ์คํธ๋ฆฌ๋ฐ ์๋ต: ๋์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ํ ์๋ฒ ์ ์ก ์ด๋ฒคํธ(SSE) ๋ง์คํฐํ๊ธฐ
์ค๋๋ ๋น ๋ฅด๊ฒ ๋ณํํ๋ ๋์งํธ ํ๊ฒฝ์์ ์ฌ์ฉ์๋ค์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ฐ์์ฑ์ด ๋ฐ์ด๋๊ณ ์ค์๊ฐ ์ ๋ฐ์ดํธ๋ฅผ ์ ๊ณตํ๊ธฐ๋ฅผ ๊ธฐ๋ํฉ๋๋ค. ๊ธฐ์กด์ ์์ฒญ-์๋ต ๋ชจ๋ธ์ ์ง์์ ์ธ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์ ๋ฌํ๋ ๋ฐ ํ๊ณ๊ฐ ์์ ์ ์์ต๋๋ค. ๋ฐ๋ก ์ด ์ง์ ์์ ์๋ฒ ์ ์ก ์ด๋ฒคํธ(Server-Sent Events, SSE)๊ฐ ์ง์ ์ผ๋ก ๋์ ์ด๊ณ ๋งค๋ ฅ์ ์ธ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ง๋ค๊ณ ์ ํ๋ ํ๋ก ํธ์๋ ๊ฐ๋ฐ์๋ค์๊ฒ ๊ฐ๋ ฅํ๋ฉด์๋ ์ข ์ข ๊ฐ๊ณผ๋๋ ๊ธฐ์ ๋ก ๋ถ์ํฉ๋๋ค. ์ด ์ข ํฉ ๊ฐ์ด๋๋ SSE์ ๊ธฐ๋ณธ ์๋ฆฌ๋ถํฐ ๊ณ ๊ธ ๊ตฌํ ์ ๋ต๊น์ง ๊ทธ ๋ณต์ก์ฑ์ ๊น์ด ํ๊ณ ๋ค์ด, ์ฌ๋ฌ๋ถ์ด ์๋๊ฐ ๋์น๋ ์ต์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ์ ์๋๋ก ์ง์ํ ๊ฒ์ ๋๋ค.
์๋ฒ ์ ์ก ์ด๋ฒคํธ(SSE) ์ดํดํ๊ธฐ
์๋ฒ ์ ์ก ์ด๋ฒคํธ(Server-Sent Events, SSE)๋ ์๋ฒ๊ฐ ๋จ์ผ์ ์ฅ๊ธฐ ์ฐ๊ฒฐ๋ HTTP ์ฐ๊ฒฐ์ ํตํด ํด๋ผ์ด์ธํธ๋ก ๋ฐ์ดํฐ๋ฅผ ํธ์ํ ์ ์๊ฒ ํด์ฃผ๋ ์น ๊ธฐ์ ์ ๋๋ค. ์๋ฐฉํฅ ํต์ ์ ๊ฐ๋ฅํ๊ฒ ํ๋ ์น์์ผ(WebSocket)๊ณผ ๋ฌ๋ฆฌ, SSE๋ ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก์ ๋จ๋ฐฉํฅ ํต์ ์ ์ํด ์ค๊ณ๋์์ต๋๋ค. ์ด๋ ํด๋ผ์ด์ธํธ๊ฐ ์ง์์ ์ผ๋ก ์๋ฒ๋ฅผ ํด๋งํ ํ์ ์์ด, ์๋ฒ๊ฐ ์ฌ๋ฌ ํด๋ผ์ด์ธํธ์๊ฒ ๋์์ ์ ๋ฐ์ดํธ, ์๋ฆผ ๋๋ ์งํ ์ํฉ ๋ณด๊ณ ๋ฅผ ๋ธ๋ก๋์บ์คํธํด์ผ ํ๋ ์๋๋ฆฌ์ค์ ํ๋ฅญํ ์ ํ์ด ๋ฉ๋๋ค.
SSE์ ์๋ ๋ฐฉ์
SSE์ ํต์ฌ์ ์ง์์ ์ธ HTTP ์ฐ๊ฒฐ์ ์์ต๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ SSE๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ฉด, ์๋ฒ๋ ์ฐ๊ฒฐ์ ์ด์ด๋๊ณ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋๋ง๋ค ์ ์กํฉ๋๋ค. ์ด๋ฌํ ์ด๋ฒคํธ๋ ์ผ๋ฐ ํ
์คํธ, ์ค ๋ฐ๊ฟ์ผ๋ก ๊ตฌ๋ถ๋ ํ์์ผ๋ก ํฌ๋งท๋ฉ๋๋ค. ๋ธ๋ผ์ฐ์ ์ ๋ค์ดํฐ๋ธ EventSource API๋ ์ฐ๊ฒฐ ๊ด๋ฆฌ, ์ด๋ฒคํธ ํ์ฑ, ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ๋ด๋นํ์ฌ ํ๋ก ํธ์๋ ๊ฐ๋ฐ์์ ๋ณต์ก์ฑ์ ์๋น ๋ถ๋ถ ์ถ์ํํด์ค๋๋ค.
SSE์ ์ฃผ์ ํน์ง:
- ๋จ๋ฐฉํฅ ํต์ : ๋ฐ์ดํฐ๋ ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก ์๊ฒฉํ๊ฒ ํ๋ฆ ๋๋ค.
- ๋จ์ผ ์ฐ๊ฒฐ: ํ๋์ ์ฅ๊ธฐ์ ์ธ HTTP ์ฐ๊ฒฐ์ด ์ ์ง๋ฉ๋๋ค.
- ํ ์คํธ ๊ธฐ๋ฐ ํ๋กํ ์ฝ: ์ด๋ฒคํธ๋ ์ผ๋ฐ ํ ์คํธ๋ก ์ ์ก๋์ด ์ฝ๊ณ ๋๋ฒ๊น ํ๊ธฐ ์ฝ์ต๋๋ค.
- ์๋ ์ฌ์ฐ๊ฒฐ: ์ฐ๊ฒฐ์ด ๋์ด์ง๋ฉด
EventSourceAPI๊ฐ ์๋์ผ๋ก ์ฌ์ฐ๊ฒฐ์ ์๋ํฉ๋๋ค. - HTTP ๊ธฐ๋ฐ: SSE๋ ๊ธฐ์กด HTTP ์ธํ๋ผ๋ฅผ ํ์ฉํ์ฌ ๋ฐฐํฌ์ ๋ฐฉํ๋ฒฝ ํต๊ณผ๋ฅผ ๋จ์ํํฉ๋๋ค.
- ์ด๋ฒคํธ ์ ํ: ์ฌ์ฉ์ ์ ์ `event` ํ๋๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฒคํธ๋ฅผ ๋ถ๋ฅํ ์ ์์ด ํด๋ผ์ด์ธํธ๊ฐ ๋ค์ํ ์ ํ์ ์ ๋ฐ์ดํธ๋ฅผ ๊ตฌ๋ณํ ์ ์์ต๋๋ค.
ํ๋ก ํธ์๋ ์คํธ๋ฆฌ๋ฐ์ SSE๋ฅผ ์ ํํ๋ ์ด์
์น์์ผ์ด ์์ ํ ์๋ฐฉํฅ ํต์ ์ ์ ๊ณตํ๋ ๋ฐ๋ฉด, SSE๋ ํน์ ์ฌ์ฉ ์ฌ๋ก, ํนํ ์๋ฒ์์ ํด๋ผ์ด์ธํธ๋ก ๋ฐ์ดํฐ๋ฅผ ํธ์ํ๋ ๊ฒ์ด ์ฃผ์ ์๊ตฌ์ฌํญ์ผ ๋ ๊ฐ๋ ฅํ ์ด์ ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฌํ ์ด์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
1. ๋จ์์ฑ๊ณผ ๊ตฌํ์ ์ฉ์ด์ฑ
์น์์ผ์ ๋นํด SSE๋ ์๋ฒ์ ํด๋ผ์ด์ธํธ ์์ธก ๋ชจ๋์์ ๊ตฌํํ๊ธฐ๊ฐ ํจ์ฌ ๊ฐ๋จํฉ๋๋ค. ์ต์ ๋ธ๋ผ์ฐ์ ์ EventSource API๋ ์ฐ๊ฒฐ ๊ด๋ฆฌ, ๋ฉ์์ง ํ์ฑ, ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ํฌํจํ ๋๋ถ๋ถ์ ์ด๋ ค์ด ์์
์ ์ฒ๋ฆฌํฉ๋๋ค. ์ด๋ ๊ฐ๋ฐ ์๊ฐ๊ณผ ๋ณต์ก์ฑ์ ์ค์ฌ์ค๋๋ค.
2. ๋ด์ฅ๋ ์ฌ์ฐ๊ฒฐ ๋ฐ ์ค๋ฅ ์ฒ๋ฆฌ
EventSource API๋ ์ฐ๊ฒฐ์ด ์ค๋จ๋๋ฉด ์๋์ผ๋ก ์ฌ์ฐ๊ฒฐ์ ์๋ํฉ๋๋ค. ์ด ๋ด์ฅ๋ ๊ฒฌ๊ณ ์ฑ์ ํนํ ๋ถ์์ ํ ๋คํธ์ํฌ ํ๊ฒฝ์์ ์ํํ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ์งํ๋ ๋ฐ ์ค์ํฉ๋๋ค. ์ฌ์ฐ๊ฒฐ ๊ฐ๊ฒฉ์ ์ค์ ํ์ฌ ์ฌ์ฐ๊ฒฐ ๋์์ ์ ์ดํ ์ ์์ต๋๋ค.
3. ํจ์จ์ ์ธ ๋ฆฌ์์ค ์ฌ์ฉ
์๋ฐฉํฅ ํต์ ์ด ํ์ ์๋ ์๋๋ฆฌ์ค์ ๊ฒฝ์ฐ, SSE๋ ์น์์ผ๋ณด๋ค ๋ฆฌ์์ค ํจ์จ์ฑ์ด ๋ ๋์ต๋๋ค. ํ์ค HTTP๋ฅผ ํ์ฉํ๋ฏ๋ก ํน๋ณํ ๊ตฌ์ฑ ์์ด๋ ํ๋ก์ ๋ฐ ๋ก๋ ๋ฐธ๋ฐ์๋ฅผ ํฌํจํ ๊ธฐ์กด ์ธํ๋ผ์์ ์ ์ง์๋ฉ๋๋ค.
4. ๋ธ๋ผ์ฐ์ ๋ฐ ๋คํธ์ํฌ ํธํ์ฑ
SSE๋ HTTP ์์ ๊ตฌ์ถ๋์์ผ๋ฉฐ ์ต์ ๋ธ๋ผ์ฐ์ ์์ ๋๋ฆฌ ์ง์๋ฉ๋๋ค. ๋ํ ํ์ค HTTP ํ๋กํ ์ฝ์ ์์กดํ๊ธฐ ๋๋ฌธ์ ๋๋๋ก ํน์ ๊ตฌ์ฑ์ด ํ์ํ ์น์์ผ ์ฐ๊ฒฐ๋ณด๋ค ์ผ๋ฐ์ ์ผ๋ก ๋ฐฉํ๋ฒฝ ๋ฐ ๋คํธ์ํฌ ์ค๊ฐ์๋ฅผ ๋ ์ํํ๊ฒ ํต๊ณผํฉ๋๋ค.
์๋ฒ ์ ์ก ์ด๋ฒคํธ ๊ตฌํํ๊ธฐ: ์ค์ฉ ๊ฐ์ด๋
SSE๋ฅผ ์ง์ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๊ฒ์ ๋ฐฑ์๋์ ํ๋ก ํธ์๋ ๊ฐ๋ฐ์ ๋ชจ๋ ํฌํจํฉ๋๋ค. ๊ตฌํ ๊ณผ์ ์ ๋จ๊ณ๋ณ๋ก ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋ฐฑ์๋ ๊ตฌํ: SSE ์ ์กํ๊ธฐ
์๋ฒ์ ์ญํ ์ HTTP ์ฐ๊ฒฐ์ ์ค์ ํ๊ณ SSE ํ์์ผ๋ก ์ด๋ฒคํธ๋ฅผ ๋ณด๋ด๋ ๊ฒ์ ๋๋ค. ๊ตฌ์ฒด์ ์ธ ๊ตฌํ์ ๋ฐฑ์๋ ์ธ์ด์ ํ๋ ์์ํฌ์ ๋ฐ๋ผ ๋ค๋ฅด์ง๋ง ํต์ฌ ์์น์ ๋์ผํฉ๋๋ค.
SSE ์ด๋ฒคํธ ํ์
์๋ฒ ์ ์ก ์ด๋ฒคํธ๋ ํน์ ๊ตฌ๋ถ ๊ธฐํธ๊ฐ ์๋ ์ผ๋ฐ ํ ์คํธ๋ก ํ์ํ๋ฉ๋๋ค. ๊ฐ ์ด๋ฒคํธ๋ ํ๋ ์ด์์ ์ค๋ก ๊ตฌ์ฑ๋๋ฉฐ ์ค ๋ฐ๊ฟ ๋ฌธ์(` `)๋ก ๋๋ฉ๋๋ค. ์ฃผ์ ํ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
data:์ค์ ๋ฐ์ดํฐ ํ์ด๋ก๋. ์ฌ๋ฌdata:๋ผ์ธ์ ํด๋ผ์ด์ธํธ์์ ์ค ๋ฐ๊ฟ ๋ฌธ์๋ก ์ฐ๊ฒฐ๋ฉ๋๋ค.event:์ด๋ฒคํธ ์ ํ์ ์ ์ํ๋ ์ ํ์ ๋ฌธ์์ด. ์ด๋ฅผ ํตํด ํด๋ผ์ด์ธํธ๋ ์ด๋ฒคํธ ์ ํ์ ๋ฐ๋ผ ๋ค๋ฅธ ํธ๋ค๋ฌ๋ก ๋ถ๊ธฐํ ์ ์์ต๋๋ค.id:๋ง์ง๋ง์ผ๋ก ์๋ ค์ง ์ด๋ฒคํธ ID๋ฅผ ๋ํ๋ด๋ ์ ํ์ ๋ฌธ์์ด. ํด๋ผ์ด์ธํธ๋ ์ฌ์ฐ๊ฒฐ ์ ์ด ID๋ฅผ `Last-Event-ID` ํค๋์ ๋ด์ ๋ค์ ๋ณด๋ผ ์ ์์ผ๋ฉฐ, ์ด๋ฅผ ํตํด ์๋ฒ๋ ์ค๋จ๋ ์ง์ ๋ถํฐ ์คํธ๋ฆผ์ ์ฌ๊ฐํ ์ ์์ต๋๋ค.retry:์ฌ์ฐ๊ฒฐ ์๊ฐ์ ๋ฐ๋ฆฌ์ด ๋จ์๋ก ๋ํ๋ด๋ ์ ํ์ ๋ฌธ์์ด.
๋น ์ค์ ์ด๋ฒคํธ์ ๋์ ์๋ฏธํฉ๋๋ค. ์ฃผ์ ์ค์ ์ฝ๋ก (`:`)์ผ๋ก ์์ํฉ๋๋ค.
์์ (Express๋ฅผ ์ฌ์ฉํ ๊ฐ๋ ์ Node.js):
```javascript app.get('/events', (req, res) => { res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); let eventCounter = 0; const intervalId = setInterval(() => { const message = { event: 'update', id: eventCounter, data: JSON.stringify({ timestamp: new Date().toISOString(), message: `Server tick ${eventCounter}` }) }; res.write(`event: ${message.event}\n`); res.write(`id: ${message.id}\n`); res.write(`data: ${message.data}\n\n`); eventCounter++; if (eventCounter > 10) { // Example: stop after 10 events clearInterval(intervalId); res.end(); } }, 1000); req.on('close', () => { clearInterval(intervalId); res.end(); }); }); ```
์ด ์์ ์์:
- ์ ์ ํ ํค๋์ธ
Content-Type: text/event-stream,Cache-Control: no-cache,Connection: keep-alive๋ฅผ ์ค์ ํฉ๋๋ค. setInterval์ ์ฌ์ฉํ์ฌ ์ฃผ๊ธฐ์ ์ผ๋ก ์ด๋ฒคํธ๋ฅผ ์ ์กํฉ๋๋ค.- ๊ฐ ์ด๋ฒคํธ๋
event,id,dataํ๋๋ก ํ์ํ๋๋ฉฐ, ์ด๋ฒคํธ์ ๋์ ์๋ฆฌ๋ ๋น ์ค์ด ๋ค๋ฐ๋ฆ ๋๋ค. - ์ธํฐ๋ฒ์ ์ ๊ฑฐํ์ฌ ํด๋ผ์ด์ธํธ์ ์ฐ๊ฒฐ ํด์ ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.
ํ๋ก ํธ์๋ ๊ตฌํ: SSE ์๋นํ๊ธฐ
ํ๋ก ํธ์๋์์๋ EventSource API๋ฅผ ์ฌ์ฉํ์ฌ SSE ์คํธ๋ฆผ์ ๋งค์ฐ ์ฝ๊ฒ ์ฐ๊ฒฐํ๊ณ ๋ค์ด์ค๋ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
EventSource API ์ฌ์ฉํ๊ธฐ
```javascript const eventSource = new EventSource('/events'); // Handle general 'message' events (when no 'event' field is specified) eventSource.onmessage = (event) => { console.log('Received generic message:', event.data); // Process event.data here const parsedData = JSON.parse(event.data); // Update UI with parsedData.message and parsedData.timestamp }; // Handle custom 'update' events eventSource.addEventListener('update', (event) => { console.log('Received update event:', event.data); const parsedData = JSON.parse(event.data); // Update UI with parsedData.message and parsedData.timestamp document.getElementById('status').innerText = `Last update: ${parsedData.message} at ${parsedData.timestamp}`; }); // Handle connection errors eventSource.onerror = (error) => { console.error('EventSource failed:', error); // Optionally, display a user-friendly error message or retry mechanism eventSource.close(); // Close the connection on error if not automatically handled }; // Handle connection opening eventSource.onopen = () => { console.log('EventSource connection opened.'); }; // Optional: Close the connection when it's no longer needed // document.getElementById('stopButton').addEventListener('click', () => { // eventSource.close(); // console.log('EventSource connection closed.'); // }); ```
์ด ํ๋ก ํธ์๋ ์์ ์์:
- ๋ฐฑ์๋ ์๋ํฌ์ธํธ๋ฅผ ๊ฐ๋ฆฌํค๋
EventSource์ธ์คํด์ค๋ฅผ ์์ฑํฉ๋๋ค. onmessage๋event์ ํ์ด ์ง์ ๋์ง ์์ ์ด๋ฒคํธ์ ๊ธฐ๋ณธ ํธ๋ค๋ฌ์ ๋๋ค.addEventListener('custom-event-name', handler)๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ฒ์์ ๋ณด๋ธ ํน์ ์ด๋ฒคํธ ์ ํ์ ๊ตฌ๋ ํ ์ ์์ต๋๋ค.onerror๋ ์ฐ๊ฒฐ ์คํจ ๋ฐ ๋คํธ์ํฌ ๋ฌธ์ ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ์ค์ํฉ๋๋ค.onopen์ ์ฐ๊ฒฐ์ด ์ฑ๊ณต์ ์ผ๋ก ์ค์ ๋์์ ๋ ํธ์ถ๋ฉ๋๋ค.eventSource.close()๋ฅผ ์ฌ์ฉํ์ฌ ์ฐ๊ฒฐ์ ์ข ๋ฃํ ์ ์์ต๋๋ค.
๊ณ ๊ธ SSE ๊ธฐ์ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
SSE๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ๊ณ ๊ฒฌ๊ณ ํ๋ฉฐ ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ณ ๊ธ ๊ธฐ์ ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ณ ๋ คํ์ญ์์ค.
1. ์ด๋ฒคํธ ID์ ์ฌ์ฐ๊ฒฐ
์๋ฒ์์ ์ด๋ฒคํธ ID๋ฅผ ๊ตฌํํ๊ณ ํด๋ผ์ด์ธํธ์์ `Last-Event-ID` ํค๋๋ฅผ ์ฒ๋ฆฌํ๋ ๊ฒ์ ๋ณต์๋ ฅ์ ์ํด ๋งค์ฐ ์ค์ํฉ๋๋ค. ์ฐ๊ฒฐ์ด ๋์ด์ง๋ฉด ๋ธ๋ผ์ฐ์ ๋ ์๋์ผ๋ก ์ฌ์ฐ๊ฒฐ์ ์๋ํ๊ณ ์์ ํ `Last-Event-ID`๋ฅผ ํฌํจํฉ๋๋ค. ๊ทธ๋ฌ๋ฉด ์๋ฒ๋ ์ด ID๋ฅผ ์ฌ์ฉํ์ฌ ๋๋ฝ๋ ์ด๋ฒคํธ๋ฅผ ๋ค์ ์ ์กํ์ฌ ๋ฐ์ดํฐ ์ฐ์์ฑ์ ๋ณด์ฅํ ์ ์์ต๋๋ค.
๋ฐฑ์๋ (๊ฐ๋ ์ ):
```javascript // When sending events: res.write(`id: ${eventCounter}\n`); // When receiving a reconnect request: const lastEventId = req.headers['last-event-id']; if (lastEventId) { console.log(`Client reconnected with last event ID: ${lastEventId}`); // Logic to send missed events starting from lastEventId } ```
2. ์ฌ์ฉ์ ์ ์ ์ด๋ฒคํธ ์ ํ
event ํ๋๋ฅผ ์ฌ์ฉํ๋ฉด ๋์ผํ SSE ์ฐ๊ฒฐ์ ํตํด ๋ค์ํ ์ ํ์ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ผ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, user_update ์ด๋ฒคํธ, notification ์ด๋ฒคํธ ๋๋ progress_update ์ด๋ฒคํธ๋ฅผ ๋ณด๋ผ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํ๋ก ํธ์๋ ๋ก์ง์ด ๋ ์ฒด๊ณํ๋๊ณ ํด๋ผ์ด์ธํธ๊ฐ ํน์ ์ด๋ฒคํธ์ ๋ฐ์ํ ์ ์์ต๋๋ค.
3. ๋ฐ์ดํฐ ์ง๋ ฌํ
SSE๋ ํ
์คํธ ๊ธฐ๋ฐ์ด์ง๋ง JSON๊ณผ ๊ฐ์ ๊ตฌ์กฐํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋ ๊ฒ์ด ์ผ๋ฐ์ ์
๋๋ค. ์๋ฒ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ง๋ ฌํํ๊ณ (์: JSON.stringify ์ฌ์ฉ) ํด๋ผ์ด์ธํธ๊ฐ ์ญ์ง๋ ฌํํ๋์ง(์: JSON.parse ์ฌ์ฉ) ํ์ธํ์ญ์์ค.
๋ฐฑ์๋:
```javascript res.write(`data: ${JSON.stringify({ type: 'status', payload: 'Processing completed' })}\n\n`); ```
ํ๋ก ํธ์๋:
```javascript eventSource.addEventListener('message', (event) => { const data = JSON.parse(event.data); if (data.type === 'status') { console.log('Status update:', data.payload); } }); ```
4. ์ฌ๋ฌ SSE ์คํธ๋ฆผ ์ฒ๋ฆฌํ๊ธฐ
ํ๋์ EventSource ์ธ์คํด์ค๋ ํ๋์ URL์๋ง ์ฐ๊ฒฐํ ์ ์์ต๋๋ค. ์ฌ๋ฌ ๊ฐ์ ๊ฐ๋ณ ์คํธ๋ฆผ์ ์์ ํด์ผ ํ๋ ๊ฒฝ์ฐ, ๊ฐ๊ฐ ๋ค๋ฅธ ์๋ํฌ์ธํธ๋ฅผ ๊ฐ๋ฆฌํค๋ ์ฌ๋ฌ EventSource ์ธ์คํด์ค๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค.
5. ์๋ฒ ๋ถํ ๋ฐ ์ฐ๊ฒฐ ์ ํ
SSE๋ ์ฅ๊ธฐ HTTP ์ฐ๊ฒฐ์ ์ฌ์ฉํฉ๋๋ค. ์๋ฒ ๋ฆฌ์์ค ์ ํ ๋ฐ ์น ์๋ฒ ๋๋ ๋ก๋ ๋ฐธ๋ฐ์์ ์ํด ๋ถ๊ณผ๋ ์ ์๋ ์ ์ฌ์ ์ธ ์ฐ๊ฒฐ ์ ํ์ ์ ์ํ์ญ์์ค. ์ธํ๋ผ๊ฐ ์ถฉ๋ถํ ์์ ๋์ ์ฐ๊ฒฐ์ ์ฒ๋ฆฌํ๋๋ก ๊ตฌ์ฑ๋์๋์ง ํ์ธํ์ญ์์ค.
6. ์ ์์ ์ธ ์ข ๋ฃ ๋ฐ ์ ๋ฆฌ
์๋ฒ๊ฐ ์ข ๋ฃ๋๊ฑฐ๋ ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ์ด ๋์ด์ง ๋, ์ด๋ฆฐ ์ฐ๊ฒฐ์ ๋ซ๊ณ ์ธํฐ๋ฒ์ ์ ๊ฑฐํ๋ ๋ฑ ๋ฆฌ์์ค๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ ๋ฆฌํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ด๋ ๋ฆฌ์์ค ๋์๋ฅผ ๋ฐฉ์งํ๊ณ ์ํํ ์ ํ์ ๋ณด์ฅํฉ๋๋ค.
7. ๋ณด์ ๊ณ ๋ ค์ฌํญ
SSE๋ HTTP ์์ ๊ตฌ์ถ๋๋ฏ๋ก HTTP์ ๋ณด์ ๊ธฐ๋ฅ์ ์์ํฉ๋๋ค. ์ ์ก ์ค์ธ ๋ฐ์ดํฐ๋ฅผ ์ํธํํ๊ธฐ ์ํด ์ฐ๊ฒฐ์ด HTTPS๋ฅผ ํตํด ์ ๊ณต๋๋์ง ํ์ธํ์ญ์์ค. ์ธ์ฆ์ ๊ฒฝ์ฐ, SSE ์ฐ๊ฒฐ์ ์ค์ ํ ๋ ํ์ค HTTP ์ธ์ฆ ๋ฉ์ปค๋์ฆ(์: ํค๋์ ํ ํฐ)์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์๋ฒ ์ ์ก ์ด๋ฒคํธ์ ์ฌ์ฉ ์ฌ๋ก
SSE๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ด๋ฒ์ํ ์ค์๊ฐ ๊ธฐ๋ฅ์ ์ํ ์ด์์ ์ธ ์๋ฃจ์ ์ ๋๋ค. ๋ช ๊ฐ์ง ์ฃผ์ ์ฌ์ฉ ์ฌ๋ก๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
1. ์ค์๊ฐ ์๋ฆผ ๋ฐ ๊ฒฝ๊ณ
์ ๋ฉ์์ง, ์น๊ตฌ ์์ฒญ, ์์คํ ์ ๋ฐ์ดํธ ๋๋ ๊ด๋ จ ํ๋์ ๋ํ ์ฆ๊ฐ์ ์ธ ์๋ฆผ์ ์ฌ์ฉ์๊ฐ ํ์ด์ง๋ฅผ ์๋ก ๊ณ ์น ํ์ ์์ด ์ ๋ฌํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์์ ๋ฏธ๋์ด ํ๋ซํผ์ SSE๋ฅผ ์ฌ์ฉํ์ฌ ์ ๊ฒ์๋ฌผ ์๋ฆผ์ด๋ ๋ค์ด๋ ํธ ๋ฉ์์ง๋ฅผ ํธ์ํ ์ ์์ต๋๋ค.
๊ธ๋ก๋ฒ ์์: ์ฑ๊ฐํฌ๋ฅด์ ํ ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ SSE๋ฅผ ์ฌ์ฉํ์ฌ ๋๊ท๋ชจ ์ธ์ถ์ด๋ ์ ๊ธ๊ณผ ๊ฐ์ ๊ณ์ข ํ๋์ ๋ํด ์ฌ์ฉ์์๊ฒ ์ค์๊ฐ์ผ๋ก ๊ฒฝ๊ณ ํ์ฌ ๊ธ์ต ๊ฑฐ๋๋ฅผ ์ฆ์ ์ธ์งํ ์ ์๋๋ก ๋ณด์ฅํฉ๋๋ค.
2. ์ค์๊ฐ ๋ฐ์ดํฐ ํผ๋
์ฃผ๊ฐ, ์คํฌ์ธ ์ ์ ๋๋ ์ํธํํ ์์ธ์ ๊ฐ์ด ์์ฃผ ๋ณ๊ฒฝ๋๋ ์ค์๊ฐ ๋ฐ์ดํฐ๋ฅผ ํ์ํฉ๋๋ค. SSE๋ ์ด๋ฌํ ํผ๋์ ์ ๋ฐ์ดํธ๊ฐ ๋ฐ์ํ ๋๋ง๋ค ํธ์ํ์ฌ ์ฌ์ฉ์์๊ฒ ์ต์ ์ ๋ณด๋ฅผ ์ ๊ณตํฉ๋๋ค.
๊ธ๋ก๋ฒ ์์: ๋ฐ๋์ ๋ณธ์ฌ๋ฅผ ๋ ๊ธ๋ก๋ฒ ๊ธ์ต ๋ด์ค ์ ๊ทธ๋ฆฌ๊ฒ์ดํฐ๋ SSE๋ฅผ ์ฌ์ฉํ์ฌ ๋ด์, ๋์ฟ, ํ๋ํฌํธ๋ฅดํธ์ ๊ฑฐ๋์์์ ์ค์๊ฐ ์ฃผ์ ์์ฅ ์ ๋ฐ์ดํธ๋ฅผ ์คํธ๋ฆฌ๋ฐํ์ฌ ์ ์ธ๊ณ ์ฌ์ฉ์์๊ฒ ์ฆ๊ฐ์ ์ธ ์์ฅ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค.
3. ์งํ๋ฅ ํ์๊ธฐ ๋ฐ ์ํ ์ ๋ฐ์ดํธ
์๋ฒ์์ ์ฅ์๊ฐ ์คํ๋๋ ์์ (์: ํ์ผ ์ ๋ก๋, ๋ณด๊ณ ์ ์์ฑ, ๋ฐ์ดํฐ ์ฒ๋ฆฌ)์ ์ํํ ๋ SSE๋ ํด๋ผ์ด์ธํธ์๊ฒ ์ค์๊ฐ ์งํ ์ํฉ ์ ๋ฐ์ดํธ๋ฅผ ์ ๊ณตํ ์ ์์ต๋๋ค. ์ด๋ ์งํ ์ค์ธ ์์ ์ ๋ํ ๊ฐ์์ฑ์ ์ ๊ณตํ์ฌ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํต๋๋ค.
๊ธ๋ก๋ฒ ์์: ๊ตญ์ ์ ์ผ๋ก ์ด์๋๋ ํด๋ผ์ฐ๋ ์คํ ๋ฆฌ์ง ์๋น์ค๋ SSE๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ๋ฌ ๋๋ฅ์ ๊ฑธ์ณ ๋์ฉ๋ ํ์ผ ์ ๋ก๋ ๋๋ ๋ค์ด๋ก๋ ์งํ ์ํฉ์ ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ค์ผ๋ก์จ ์์น์ ๊ด๊ณ์์ด ์ผ๊ด๋๊ณ ์ ์ตํ ๊ฒฝํ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
4. ์ค์๊ฐ ์ฑํ ๋ฐ ๋ฉ์์ง (์ ํ๋ ๋ฒ์)
์ผ๋ฐ์ ์ผ๋ก ์์ ํ ์๋ฐฉํฅ ์ฑํ ์๋ ์น์์ผ์ด ์ ํธ๋์ง๋ง, SSE๋ ์ฑํ ๋ฐฉ์์ ๋ฉ์์ง๋ฅผ ์์ ํ๋ ๊ฒ๊ณผ ๊ฐ์ ๋ ๊ฐ๋จํ ๋จ๋ฐฉํฅ ๋ฉ์์ง ์๋๋ฆฌ์ค์ ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ์ฌ์ฉ์๊ฐ ์์ฃผ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๋ ๋ํํ ์ฑํ ์ ๊ฒฝ์ฐ, ์กฐํฉ ๋๋ ์น์์ผ ์๋ฃจ์ ์ด ๋ ์ ํฉํ ์ ์์ต๋๋ค.
5. ๋ชจ๋ํฐ๋ง ๋ฐ ๋ถ์ ๋์๋ณด๋
์์คํ ์ํ, ์ฑ๋ฅ ๋ฉํธ๋ฆญ ๋๋ ์ฌ์ฉ์ ํ๋์ ์ค์๊ฐ ๋ชจ๋ํฐ๋ง์ด ํ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ SSE์ ์ด์ ์ ๋๋ฆด ์ ์์ต๋๋ค. ์๋ก์ด ๋ฐ์ดํฐ ํฌ์ธํธ๊ฐ ์ฌ์ฉ ๊ฐ๋ฅํด์ง๋ฉด ๋์๋ณด๋๊ฐ ๋์ ์ผ๋ก ์ ๋ฐ์ดํธ๋ ์ ์์ต๋๋ค.
๊ธ๋ก๋ฒ ์์: ๋ค๊ตญ์ ๋ฌผ๋ฅ ํ์ฌ๋ SSE๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ํ ์๊ฐ๋์ ์ง์ญ์ ๊ฐ๋ก์ง๋ฅด๋ ํธ๋ญ ๋ฐ ์ ๋ฐ์ ์ค์๊ฐ ์์น์ ์ํ๋ก ๋์๋ณด๋๋ฅผ ์ ๋ฐ์ดํธํ ์ ์์ต๋๋ค.
6. ํ์ ํธ์ง (๋ถ๋ถ์ )
ํ์ ํ๊ฒฝ์์ SSE๋ ์ปค์ ์์น๋ ํ ์คํธ ์ ๋ฐ์ดํธ์ ๊ฐ์ด ๋ค๋ฅธ ์ฌ์ฉ์๊ฐ ๋ณ๊ฒฝํ ๋ด์ฉ์ ๋ชจ๋ ์ฐ๊ฒฐ๋ ํด๋ผ์ด์ธํธ์๊ฒ ๋ธ๋ก๋์บ์คํธํ๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค. ์์ ํ ์ค์๊ฐ ํ์ ํธ์ง์ ์ํด์๋ ๋ ์ ๊ตํ ์ ๊ทผ ๋ฐฉ์์ด ํ์ํ ์ ์์ต๋๋ค.
SSE vs. ์น์์ผ: ์ฌ๋ฐ๋ฅธ ๋๊ตฌ ์ ํํ๊ธฐ
์ธ์ SSE๋ฅผ ์ฌ์ฉํ๊ณ ์ธ์ ์น์์ผ์ด ๋ ์ ํฉํ์ง ์ดํดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๋ ๊ธฐ์ ๋ชจ๋ ์ค์๊ฐ ํต์ ์ ํ์์ฑ์ ํด๊ฒฐํ์ง๋ง, ์๋ก ๋ค๋ฅธ ์ฃผ์ ๋ชฉ์ ์ ์ ๊ณตํฉ๋๋ค.
SSE๋ฅผ ์ฌ์ฉํด์ผ ํ ๋:
- ์๋ฒ-ํด๋ผ์ด์ธํธ ๋ธ๋ก๋์บ์คํธ: ์ฃผ์ ์๊ตฌ์ฌํญ์ด ์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ์๊ฒ ์ ๋ฐ์ดํธ๋ฅผ ๋ณด๋ด๋ ๊ฒ์ผ ๋.
- ๋จ์์ฑ์ด ํต์ฌ์ผ ๋: ๊ตฌํ์ ์ฉ์ด์ฑ๊ณผ ์ ์ ์ค๋ฒํค๋๊ฐ ์ฐ์ ์๋๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ.
- ๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ: ํด๋ผ์ด์ธํธ๊ฐ ๋์ผํ ์ฑ๋์ ํตํด ์๋ฒ์ ์์ฃผ ๋ฉ์์ง๋ฅผ ๋ณด๋ผ ํ์๊ฐ ์์ ๋.
- ๊ธฐ์กด ์ธํ๋ผ์์ ํธํ์ฑ: ๋ณต์กํ ๊ตฌ์ฑ ์์ด ๋ฐฉํ๋ฒฝ ๋ฐ ํ๋ก์์์ ํธํ์ฑ์ ๋ณด์ฅํด์ผ ํ ๋.
- ์๋ฆผ, ๋ผ์ด๋ธ ํผ๋, ์งํ ์ํฉ ์ ๋ฐ์ดํธ: ์ฌ์ฉ ์ฌ๋ก ์น์ ์์ ์์ธํ ์ค๋ช ํ ๋๋ก.
์น์์ผ์ ์ฌ์ฉํด์ผ ํ ๋:
- ์๋ฐฉํฅ ํต์ : ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ์์ฃผ ๊ทธ๋ฆฌ๊ณ ์ค์๊ฐ์ผ๋ก ๋ณด๋ด์ผ ํ ๋(์: ๋ํํ ๊ฒ์, ์ ์ฒด ์ฑํ ์ ํ๋ฆฌ์ผ์ด์ ).
- ์๋ฐฉํฅ ๋ชจ๋ ๋ฎ์ ์ง์ฐ ์๊ฐ: ์ก์์ ๋ชจ๋์ ๊ฐ๋ฅํ ๊ฐ์ฅ ๋ฎ์ ์ง์ฐ ์๊ฐ์ด ์ค์ํ ๋.
- ๋ณต์กํ ์ํ ๊ด๋ฆฌ: ๋จ์ํ ๋ฐ์ดํฐ ํธ์๋ฅผ ๋์ด ๋ณต์กํ ํด๋ผ์ด์ธํธ-์๋ฒ ์ํธ ์์ฉ์ด ํ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฝ์ฐ.
SSE๋ ํน์ ์ค์๊ฐ ๋ฌธ์ ๋ฅผ ์ํ ์ ๋ฌธํ๋ ๋๊ตฌ์ ๋๋ค. ๊ทธ ๋ฌธ์ ๊ฐ ์๋ฒ-ํด๋ผ์ด์ธํธ ์คํธ๋ฆฌ๋ฐ์ผ ๋, SSE๋ ์ข ์ข ๋ ํจ์จ์ ์ด๊ณ ๊ฐ๋จํ ์๋ฃจ์ ์ ๋๋ค.
๊ฒฐ๋ก
์๋ฒ ์ ์ก ์ด๋ฒคํธ๋ ์๋ฒ์์ ํ๋ก ํธ์๋๋ก ์ค์๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๊ธฐ ์ํ ๊ฒฌ๊ณ ํ๊ณ ์ฐ์ํ ์๋ฃจ์ ์ ์ ๊ณตํฉ๋๋ค. SSE์ ์๋ ๋ฐฉ์์ ์ดํดํ๊ณ ๋ชจ๋ฒ ์ฌ๋ก์ ๋ฐ๋ผ ๊ตฌํํจ์ผ๋ก์จ ๊ฐ๋ฐ์๋ ์ฌ์ฉ์ ๊ฒฝํ์ ํฌ๊ฒ ํฅ์์์ผ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋์ฑ ๋์ ์ด๊ณ ๋ฐ์์ฑ์ด ๋ฐ์ด๋๋ฉฐ ๋งค๋ ฅ์ ์ผ๋ก ๋ง๋ค ์ ์์ต๋๋ค. ๋ผ์ด๋ธ ๋์๋ณด๋, ์๋ฆผ ์์คํ ๋๋ ๋ฐ์ดํฐ ํผ๋๋ฅผ ๊ตฌ์ถํ๋ , SSE๋ฅผ ์ฑํํ๋ฉด ์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ์ํด ์ง์ ์ผ๋ก ํ๋์ ์ด๊ณ ์ํธ์์ฉ์ ์ธ ์น ๊ฒฝํ์ ๋ง๋ค ์ ์์ต๋๋ค.
์ค๋ ๋ฐ๋ก SSE๋ฅผ ์คํํด๋ณด๊ณ ์ง์ ํ ์คํธ๋ฆฌ๋ฐ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ฌ๋ ฅ์ ์ด์ด๋ณด์ธ์!